// 用于实现各种弹框 // 消息提示 // 

import { max } from "lodash-es"
import { h, VNode, render, Slots, unref, Ref } from "vue";
import {IPackAntvX6} from "pack-antv-x6"
import {t} from "../../i18n/index"


export default class Box {
    constructor() {
        
    }
    body = document.body;
    lockCT = 0;
    openedBox = new Set<IPackAntvX6.DialogEl | IPackAntvX6.ProverEl | IPackAntvX6.DrawerEl | IPackAntvX6.BoxEl>();
    closeAll(){
        for(const e of this.openedBox){
            e.close();
        }
    }
    getCurrentBox = () => Array.from(this.openedBox).pop();
    // 弹框
    dialog(node: VNode | ((e:IPackAntvX6.DialogEl) => VNode), options: { title?: VNode | string | Ref<string>, parent?: HTMLElement, submitText?: string, cancelText?: string, showFooter?: boolean, showCancel?: boolean, showSubmit?: boolean,model?:boolean } = {}) {
        let { title, parent = document.body, showFooter = true, showCancel = true, showSubmit = true, cancelText = t('box-cancel-text'), submitText = t('box-submit-text') ,model = true} = options;

        if (!showSubmit) {
            cancelText = t('box-close-text')
        }

        if (!showCancel && !showSubmit) {
            showFooter = false;
        }

        const callback: any = { submit: {}, cancel: {}, finish: {} }
        const submit = (call?: (e?: Event) => Promise<boolean | void>) => {
            return new Promise((resolve, reject) => {
                callback.submit.call = call;
                callback.submit.resolve = () => resolve(true);
                callback.submit.reject = (arg?: any) => reject(arg);
            })
        }
        const cancel = (call?: (e?: Event) => Promise<boolean | void>) => {
            return new Promise((resolve, reject) => {
                callback.cancel.call = call;
                callback.cancel.resolve = () => resolve(true);
                callback.cancel.reject = (arg?: any) => reject(arg);;
            })
        }
        const finish = (call?: (e?: Event) => Promise<boolean | void>) => {
            return new Promise((resolve, reject) => {
                callback.finish.call = call;
                callback.finish.resolve = () => resolve(true);
                callback.finish.reject = (arg?: any) => reject(arg);;
            })
        }
        const handleSubmit = async (e: any) => {
            let res: any
            if (callback.submit.call) {
                res = await callback.submit.call(e);
            }
            if (callback.finish.call) {
                res = await callback.finish.call(e)
            }
            if (res !== false) {
                if (callback.submit.resolve) {
                    callback.submit.resolve();
                }
                if (callback.finish.resolve) {
                    callback.finish.resolve();
                }
                close();
            } else {
                if (callback.submit.reject) {
                    callback.submit.reject();
                }
                if (callback.finish.reject) {
                    callback.finish.reject();
                }
            }
        }
        const handleCancel = async (e: any) => {
            let res: any
            if (callback.cancel.call) {
                res = await callback.cancel.call(e);
            }
            if (callback.finish.call) {
                res = await callback.finish.call(e)
            }
            if (res !== false) {
                if (callback.cancel.resolve) {
                    callback.cancel.resolve();
                }
                if (callback.finish.resolve) {
                    callback.finish.resolve();
                }
                close();
            } else {
                if (callback.cancel.reject) {
                    callback.cancel.reject();
                }
                if (callback.finish.reject) {
                    callback.finish.reject();
                }
            }
        }
        let el:HTMLElement | undefined = undefined;
        const close = () => el && (el.className = `${cls} scale-out-center`);
        //
        const res: IPackAntvX6.DialogEl= {el, close, submit, cancel, finish,handleSubmit,handleCancel}
        const cls = "absolute left-50% top-50% translate--50% shadow-lg bg-#ffffffaa backdrop-blur-lg p-8px rd-8px"
        const content = h('div', { class: `${cls} scale-in-center w-fit ` }, [
            title ? h('div', { class: "w-full p-b-8px flex items-center justify-between" }, [
                h('b', { class: "w-80% truncate " }, unref(title)),
                h('div', { class: "icon-btn p-4px rd-4px" ,onClick:handleCancel }, h('i', { class: "block i-mdi:close w-1em h-1em" }))
            ]) : undefined,
            h('div', { class: "rd-8px overflow-hidden relative w-fit h-fit " }, typeof node == 'function' ? node(res) : node),
            // showFooter ? h('div', { class: "flex items-center justify-end gap-24px p-t-8px" }, [
            //     showCancel ? h('div', { class: "flex items-center gap-4 icon-btn", onClick: handleCancel }, [h('i', { class: "i-mdi:close w-1em h-1em" }), h('span', {}, cancelText)]) : undefined,
            //     showSubmit ? h('div', { class: "flex items-center gap-4 icon-btn", onClick: handleSubmit }, [h('i', { class: "i-humbleicons:check w-1em h-1em" }), h('span', {}, submitText)]) : undefined,
            // ]) : undefined

        ])
        el = this.addNode(model ? h('div',{class:"w-100vw h-100vh fixed left-0 top-0 bg-#00000011"},content) : content, parent)
        el.style.zIndex = this.maxIndex(parent) + '';
        if(model){el = el.childNodes[0] as HTMLElement};
        // <div class="i-humbleicons:check w-1em h-1em"></div> <div class="i-mdi:close w-1em h-1em"></div>
        el.addEventListener('animationend', (evt: any) => {
            if (evt.animationName.includes('out')) {
                model? el.parentElement?.remove() :el.remove();
                this.openedBox.delete(res);
            } else {
                el.className = cls;
            }
        })

        
        
        this.openedBox.add(res)

        return res;

    }
    // 模态框
    model() { }

    // 抽屉
    // drawer(node:VNode|((e:IPackAntvX6.DrawerEl) => VNode),options:IPackAntvX6.DrawerProps & {parent:HTMLElement}){
    //     const {parent,direction = 'bottom',autoRemove = true,...ps} = options;
    //     let el:HTMLElement|undefined = undefined;
    //     const open = () => {el && (el.className = `${cls} slide-in-${direction}`);}
    //     const close = () => {el && (el.className = `${cls} slide-out-${direction}`)}
    //     const res = {el,open,close}
    //     const content = h(DrawerPanel,{...ps,direction},{default:() => [typeof node == 'function' ? node(res) : node]});
    //     //
    //     el = this.addNode(content,parent);
    //     const cls = el.className;
    //     el.style.zIndex = this.maxIndex(parent) + '';
    //     el.className = `${cls} op-0`;
    //     el.addEventListener('animationend', (evt: any) => {
    //         if (evt.animationName.includes('out')) {
    //             if(autoRemove){
    //                 el.remove();
    //                 this.openedBox.delete(res)
    //             }
    //             else{
    //                 el.className = `${cls} display-none`
    //             }
                
    //         }else{
    //             el.className = cls;
    //         }
    //     })
        
    //     //
        
    //     this.openedBox.add(res)
    //     return res


    // }
    // 消息提示 <div class="i-hugeicons:cancel-02 w-1em h-1em"></div> <div class="i-hugeicons:tick-03 w-1em h-1em"></div>
    tip(msg: string | VNode, options: { duration?: number, parent?: HTMLElement, type?: "success" | "error" | "info" | "warn" | "fail", class?: string } = {}) {
        const { parent, class: className = '', duration = 3000, type = 'success' } = options;

        const cls = `absolute max-w-50vw w-fit text-wrap top-20 left-50% translate-x--50% backdrop-blur-md bg-#ffffffaa shadow-lg rd-4 p-x-8 p-y-4 ui-box-tip is-status-${type} ${className}`

        const el = this.addNode(h('div', { class: `${cls} slide-in-top` }, msg), parent)
        if (!el) return;
        el.style.zIndex = this.maxIndex(parent) + '';
        el.addEventListener('animationend', (evt: any) => {
            if (evt.animationName.includes('out')) {
                el.remove();
                this.openedBox.delete(res)
            } else {
                el.className = cls;
            }
        })
        const close = () => el.className = `${cls} slide-out-top`
        duration > 0 && setTimeout(() => close(), duration)
        const res = { el, close }
        this.openedBox.add(res)
        return res
    }
    // 确认框
    confirm(msg:string|VNode,options:{title?:string} = {}){

    }
    // 动态文本框 文本动态加载的
    // 展示框
    // 自动移除的悬浮面板
    panel() { }
    // 浮出层
    popver(nodes: VNode | VNode[] | Slots, options: { class?: string, direction?: "bottom" | "left" | "top" | "right", parent?: HTMLElement,autoRemove?:boolean } = {}) {
        const { parent,direction:dir,autoRemove = false } = options;
        //
        const cls = (options.class || '') + ' absolute w-fit h-fit p-8 backdrop-blur-md rd-6 shadow-md'
        const el = this.addNode(h('div', { class: cls + ' display-none' }, nodes), parent) as HTMLDivElement
        let timeHandle: any = undefined;
        //
        const open = (e?: Event|string, direction?: "bottom" | "left" | "top" | "right", offset?: number) => {
            window.clearTimeout(timeHandle);
            if (e) {
                // this.prevent(e);
                const style = typeof e == 'string' ? e : this.pos(e, direction || dir, offset).style
                //
                console.log('=====',style)
                el.setAttribute('style', style)
            }
            el.className = cls + ' swing-in-top-fwd';
            el.style.zIndex = this.maxIndex(parent) + '';
        }
        const close = () => { timeHandle = setTimeout(() => { el.className = cls + ' swing-out-top-bck z-0'; el.style.zIndex = '0'; }, 100); }
        //
        el?.addEventListener('animationend', (evt: any) => {
            if (evt.animationName.includes('out')) {
                autoRemove ? el.remove() : el.className = cls + ' display-none';
            }
        })
        el?.addEventListener('mouseenter', (e) => {this.prevent(e);open();})
        el?.addEventListener('mouseleave', (e) => {this.prevent(e);close();})
        //
        const res = { el, open, close };
        return res
    }
    //
    pos(e: Event, direction: "bottom" | "left" | "top" | "right" = 'bottom', offset = 10) {
        const { /* offsetX: tx, offsetY: ty, */ target } = e as any;
        const p = target?.parentNode as HTMLElement;
        const parent = p?.parentNode || p;
        const { offsetLeft: cx, offsetTop: cy, offsetWidth: cw } = target || {};
        const { offsetWidth: pw, offsetHeight: ph, offsetLeft: px, offsetTop: py } = p || {};
        const { offsetWidth: fw } = parent as HTMLElement;
        //
        const x = px + cx;
        const y = py + cy;

        let top = y;
        let left = x;
        let bottom = py - offset;
        let right = fw - x + offset;
        let style = ''
        switch (direction) {
            case "bottom": top = py + ph + offset; break;
            case "top": style = `bottom:${bottom}px;left:${x}px;`; break;
            case "left": style = `right:${right}px;top:${top}px;`; break;
            // case "top":style=`bottom:${py - offset}px;left:${x}px;`;break;
            // case "left":style=`right:${fw - x - offset}px;top:${y}:px;`;break;
            case "right": left = x + cw + offset; break;
        }
        style = style || `top:${top}px;left:${left}px`;
        // const x = px + cx - 8;
        // const y = py + cy + ph;

        return { x, y, parent, style, cw, pw, fw, top, left, bottom, right }
    }
    // @ts-ignore 把元素添 渲染出来，并返回元素本身
    addNode(node: VNode, parent: HTMLElement = document.body) {
        const fragment = document.createDocumentFragment();
        // @ts-ignore
        render(node, fragment)
        const e = fragment.childNodes[0] as HTMLElement;
        parent.appendChild(fragment)
        return e;
    }

    prevent(e:Event){e.stopPropagation();e.preventDefault();}
    maxIndex(parent = this.body) { return 1 + (max([...parent.querySelectorAll('*')].map(e => +window.getComputedStyle(e).zIndex || 0).filter(n => n > 0)) || 0); }

}